import { ThreeApplication } from "./ThreeApplication";
import { EventsDispatch } from "../map/EventsDispatch";
import { Camera } from "../map/Camera";
import { Map } from "../map/Map";
import Size from "../renderExtension/types/Size";
import Config from "./constants/Config";
import Const from "./constants/Const";
import { Point } from "../renderExtension/types/Point";
import Mouse from "../processor/Mouse";
import { Light } from "../map/Light";
import { BackGround } from "../map/BackGround";
import { PostProcess } from "../map/PostProcess";
import { Vector3 } from "three";
import Stats from "three/examples/jsm/libs/stats.module";
import Events from "./constants/Events";
import MeshUtil from "../renderExtension/utils/MeshUtil";
import Orbit from "../processor/Orbit";
import { WidgetContainer } from "../Docs";
/**
 * App主对象
 */
class App extends EventsDispatch {
    public div: string = '';
    public three: ThreeApplication;
    public options;
    private static instance: App;

    /**
     * 地图对象
     */
    public map: Map;
    /**
     * 相机对象
     */
    public camera: Camera;
    /**
     * 鼠标事件对象
     */
    public mouse: Mouse;
    /**
     * 灯光对象
     */
    public light: Light;
    /**
     * 场景背景
     */
    public background: BackGround;
    /**
     * 后处理通道
     */
    public postProcess: PostProcess;
    /**
     * DOM对象
     */
    public ui: WidgetContainer;
    /**
     * 性能检测对象
     */
    public stats: Stats;
    /**
     * 构造函数
     * @param div 初始化三维场景的div对象，传div的id字符串即可
     * @param options 参数较多，请参照教程文档APP对象章节
     */

    constructor(div: string, options: any) {
        super();
        this.div = div;
        App.instance = this;
        //按顺序执行初始化操作，不能随意调换初始化顺序
        this.initOptions(options);
        this.initThree();
        this.initCamera(options);
        this.initLight();
        this.initMouse();
        this.initBackGround();
        this.initTileMap();
        this.initPostProcess();
        this.initUI();
    }

    private initOptions(parameter) {
        let options: any = {};
        options.Map = Object.assign(Config.Map, parameter);

        options.Camera = Object.assign(Config.Camera, parameter);
        options.Scene = Object.assign(Config.Scene, parameter);
        options.Render = Object.assign(Config.Render, parameter);
        options.Light = Object.assign(Config.Light, parameter);
        options.BackGround = Object.assign(Config.BackGround, parameter);
        options.ShapeConfig = Object.assign(Config.ShapeConfig, parameter);
        this.options = options;
    }

    /**
     * 初始化Threejs核心对象，必须优先执行
     */
    private initThree() {
        this.three = new ThreeApplication(this.options);
    }
    /**
     * 初始化地图对象
     */
    private initTileMap() {
        if (this.options.Map.maxZoom < this.options.Map.minZoom) {
            console.log('地图最小最大层级设置有误，致使地图初始化失败');
        }

        this.map = new Map();
        this.map.zoom = this.camera.getMapLevel();

        //将map对象添加至threejs场景中
        this.three.scene.add(this.map);
        this.camera.orbit.update();
        this.map.visible = this.options.Map.enableMap;
        this.map.load();

        this.fireEvent(Events.MapLoadFinish);
    }

    /**
     * 初始化鼠标操作对象
     */
    private initMouse() {
        this.mouse = new Mouse();
    }

    /**
     * 初始化背景
     */
    private initBackGround() {
        this.background = new BackGround();
    }

    /**
     * 初始化着色通道
     */
    private initPostProcess() {
        this.postProcess = new PostProcess();
    }

    /**
     * 初始化相机
     */
    private initCamera(parameter) {
        this.camera = new Camera();
        let cameraPosition = new Point(this.options.Camera.position[0], this.options.Camera.position[1], this.options.Camera.position[2]).toEPSGWeb();
        this.three.camera.position.copy(cameraPosition);
        this.camera.position = this.three.camera.position;
        this.options.Camera.position = this.camera.position;

        this.options.Camera.lookAt[2] = 0;
        let lookAtTarget = new Point(this.options.Camera.lookAt[0], this.options.Camera.lookAt[1], this.options.Camera.lookAt[2]).toEPSGWeb();
        let target = new Vector3(lookAtTarget.x, lookAtTarget.y, lookAtTarget.z);
        this.camera.lookAt(target);

        this.camera.orbit = new Orbit(this.three.camera);

    }

    /**
     * 初始化灯光
     */
    private initLight() {
        this.light = new Light();
    }

    /**
     * 初始化UI
     */
    private initUI() {
        this.ui = new WidgetContainer();
    }

    /**
     * 添加对象
     * @param element 对象或图层
     */
    public add(element) {
        this.three.scene.add(element);
    }

    /**
     * 删除对象
     * @param element 对象或图层
     */
    public remove(element) {
        this.three.scene.remove(element);
        MeshUtil.dispose(element);
    }

    /**
     * 获取场景尺寸
     * @returns Size对象
     */
    public getSize(): Size {
        let container = document.getElementById(this.div);
        let width = container.offsetWidth;
        if (width < 1) {
            width = parseInt(container.style.width);
        }

        let height = document.getElementById(this.div).offsetHeight;
        if (height < 1) {
            height = parseInt(container.style.height);
        }
        return new Size(width, height);
    }

    /**
     * 获取App实例对象
     * @returns  App实例
     */
    public static getInstance(): App {
        return App.instance;
    }

    /**
     * 在场景中根据uuid查找对象
     * @param uuid 对象uuid
     * @returns 场景对象，若没有查找到返回null
     */
    public getObjectById(uuid: string) {
        //查找scene下面符合条件的对象(非traverse模式，可以保证最高性能)
        for (let i = 0; i < this.three.scene.children.length; i++) {
            //Map底图不参与查找
            if (!(this.three.scene.children[i] instanceof Map)) {
                if (this.three.scene.children[i].uuid == uuid)
                    return this.three.scene.children[i];

                //若对象是图层类型，则遍历一次改图层下的子对象
                if (this.three.scene.children[i].type == 'Layer') {
                    for (let j = 0; j < this.three.scene.children[i].children.length; j++) {
                        if (this.three.scene.children[i].children[j].uuid == uuid)
                            return this.three.scene.children[i].children[j];
                    }
                }
            }
        }

        return null;
    }

    /**
     * 开启性能检测组件
     */
    public openStats() {
        if (!this.stats)
            this.stats = new Stats();
        //默认0代表显示帧率 1为两帧的刷新间隔 2为内存占用
        this.stats.showPanel(0);
        //改为右侧对齐
        this.stats.dom.style.removeProperty('left');
        this.stats.dom.style.right = '0px';

        this.stats.update();
        document.body.appendChild(this.stats.dom);
    }
    /**
     * 关闭性能检测组件
     */
    public closeStats() {
        if (this.stats) {
            document.body.removeChild(this.stats.dom);
            this.stats = null;
        }
    }

    public dispose(){
         this.map.dispose();
         this.mouse.dispose();
         
         let scene = this.three.scene;
         let meshArray = [];
         scene.children.forEach(element => {
            meshArray.push(element);
         });

         meshArray.forEach(element => {
            console.log(element);
            if(element['dispose']){
                element['dispose']();
            }
            MeshUtil.dispose(element);
         });
    }
}


export { App };